#include <stdio.h>
#include <rk_debug.h>
#include <rk_mpi_aenc.h>
#include <rk_mpi_ai.h>
#include <rk_mpi_ao.h>
#include <rk_mpi_mb.h>
#include <rk_mpi_sys.h>
extern int duiplus_init();
extern int duiplusFeedBuff(char *buff, int len);
int rkipc_ao_init() {
	int ret;
	AIO_ATTR_S aoAttr;
	memset(&aoAttr, 0, sizeof(AIO_ATTR_S));

	snprintf(aoAttr.u8CardName, sizeof(aoAttr.u8CardName), "hw:0,0");
	printf("aoAttr.u8CardName is %s\n", aoAttr.u8CardName);

	aoAttr.soundCard.channels = 2;
	aoAttr.soundCard.sampleRate = 16000;
        aoAttr.soundCard.bitWidth = AUDIO_BIT_WIDTH_16;
        aoAttr.enBitwidth = AUDIO_BIT_WIDTH_16;

	aoAttr.enSamplerate = 16000;
	aoAttr.enSoundmode = AUDIO_SOUND_MODE_STEREO;
	aoAttr.u32FrmNum = 4;
	// aoAttr.u32PtNumPerFrm = rk_param_get_int("audio.0:frame_size", 1024);
        aoAttr.u32PtNumPerFrm = 1152;
	aoAttr.u32EXFlag = 0;
	aoAttr.u32ChnCnt = 2;

	ret = RK_MPI_AO_SetPubAttr(0, &aoAttr);
	if (ret)
		printf("RK_MPI_AO_SetPubAttr fail %#x\n", ret);

	ret = RK_MPI_AO_Enable(0);
	if (ret)
		printf("RK_MPI_AO_Enable fail %#x\n", ret);
	ret = RK_MPI_AO_EnableChn(0, 0);
	if (ret)
		printf("RK_MPI_AO_EnableChn fail %#x\n", ret);
	ret = RK_MPI_AO_SetTrackMode(0, AUDIO_TRACK_OUT_STEREO);
	if (ret)
		printf("RK_MPI_AO_EnableChn fail %#x\n", ret);

    int volume = 30;
    ret = RK_MPI_AO_SetVolume(0, volume);
    if (ret)
		printf("RK_MPI_AO_SetVolume fail %#x\n", ret);
    else {
        printf("RK_MPI_AO_SetVolume success, volume = %d\n", volume);
    }

	return 0;
}

int rkipc_ao_write(unsigned char *data, int data_len) {
	int ret;
	AUDIO_FRAME_S frame;
	MB_EXT_CONFIG_S extConfig;
	memset(&frame, 0, sizeof(frame));
	frame.u32Len = data_len;
	frame.u64TimeStamp = 0;
	frame.enBitWidth = AUDIO_BIT_WIDTH_16;
	frame.enSoundMode = AUDIO_SOUND_MODE_MONO;
	frame.bBypassMbBlk = RK_FALSE;

	memset(&extConfig, 0, sizeof(extConfig));
	extConfig.pOpaque = data;
	extConfig.pu8VirAddr = data;
	extConfig.u64Size = data_len;
	RK_MPI_SYS_CreateMB(&(frame.pMbBlk), &extConfig);

	ret = RK_MPI_AO_SendFrame(0, 0, &frame, 1000);
	if (ret)
		printf("send frame fail, result = %#x\n", ret);
	RK_MPI_MB_ReleaseMB(frame.pMbBlk);

	if (data_len <= 0) {
		printf("eof\n");
		RK_MPI_AO_WaitEos(0, 0, -1);
	}

	return 0;
}

int rkipc_ao_deinit() {
	int ret;
	ret = RK_MPI_AO_DisableChn(0, 0);
	if (ret)
		printf("RK_MPI_AO_DisableChn fail %#x\n", ret);
	ret = RK_MPI_AO_Disable(0);
	if (ret)
		printf("RK_MPI_AO_Disable fail %#x\n", ret);

	return 0;
}

#define AO_FREAD_SIZE 1024 * 4
void mpi_play(char *path) {
    if (!path) {
        printf("mpi_play, path is null, return\n");
        return;
    }

    printf("mpi_play...\n");
    RK_MPI_SYS_Init();

    //while(1) {
		printf("test ao begin...... \n");
		rkipc_ao_init();
		// FILE *fp = fopen("/oem/usr/share/speaker_test.wav", "rb");
        //FILE *fp = fopen("/tmp/cap_out.pcm", "rb");
        FILE *fp = fopen(path, "rb");
		int size = AO_FREAD_SIZE;
		char *tmp_data;
		tmp_data = malloc(AO_FREAD_SIZE);
		while (size > 0) {
			memset((void *)tmp_data, 0, AO_FREAD_SIZE);
			size = fread(tmp_data, 1, AO_FREAD_SIZE, fp);
			rkipc_ao_write(tmp_data, AO_FREAD_SIZE);
		}
		rkipc_ao_write(tmp_data, 0);
		free(tmp_data);
		fclose(fp);
		rkipc_ao_deinit();
		printf("test ao end...... \n");
	//} 
}


/********audio record*********************/
RK_S32 test_open_device_ai() {
    AUDIO_DEV aiDevId = 0;
    AUDIO_SOUND_MODE_E soundMode;

    //wqy aiDevId = 0
    printf("test_open_device_ai, aiDevId = %d\n", aiDevId);
    AIO_ATTR_S aiAttr;
    RK_S32 result;
    memset(&aiAttr, 0, sizeof(AIO_ATTR_S));

    snprintf((char *)(aiAttr.u8CardName), sizeof(aiAttr.u8CardName), "hw:0,0");
    //wqy u8CardName = hw:0,0
    printf("test_open_device_ai, u8CardName = %s\n", aiAttr.u8CardName);

    aiAttr.soundCard.channels = 2;
    aiAttr.soundCard.sampleRate = 16000;
    aiAttr.soundCard.bitWidth = AUDIO_BIT_WIDTH_16;

    //wqy channels = 2, sampleRate = 16000, bitWidth = 1
    printf("channels = %d, sampleRate = %d, bitWidth = %d\n", aiAttr.soundCard.channels, aiAttr.soundCard.sampleRate, aiAttr.soundCard.bitWidth);

    //wqy bitWidth = 1
    aiAttr.enBitwidth = AUDIO_BIT_WIDTH_16;
    aiAttr.enSamplerate = 16000;
    
    //wqy enSamplerate = 16000
    printf("enSamplerate = %d\n", aiAttr.enSamplerate);
    // soundMode = ai_find_sound_mode(ctx->s32Channel);
    // if (soundMode == AUDIO_SOUND_MODE_BUTT) {
    //     goto __FAILED;
    // }

    //wqy soundMode = 1
    aiAttr.enSoundmode = AUDIO_SOUND_MODE_MONO;
    printf("soundMode = %d\n",  aiAttr.enSoundmode);
    aiAttr.u32FrmNum = 4;
    aiAttr.u32PtNumPerFrm = 1024;
    //wqy u32FrmNum = 4, u32PtNumPerFrm = 1024
    printf("u32FrmNum = %d, u32PtNumPerFrm = %d\n", aiAttr.u32FrmNum, aiAttr.u32PtNumPerFrm);

    // if (!ctx->s32DataReadEnable)
        aiAttr.u32EXFlag = 0;
    // else
    //     aiAttr.u32EXFlag = 1;

    //wqy u32EXFlag = 0
    printf("u32EXFlag = %d\n", aiAttr.u32EXFlag);
    aiAttr.u32ChnCnt = 2;

    result = RK_MPI_AI_SetPubAttr(aiDevId, &aiAttr);
    if (result != 0) {
        RK_LOGE("ai set attr fail, reason = %d", result);
        goto __FAILED;
    }

    result = RK_MPI_AMIX_SetControl(aiDevId, "ADC ALC Left Volume", (char *)"22");
    if (result != RK_SUCCESS) {
        RK_LOGE("ai set alc left voulme fail, reason = %x", result);
        goto __FAILED;
    }

    result = RK_MPI_AMIX_SetControl(aiDevId, "ADC ALC Right Volume", (char *)"22");
    if (result != RK_SUCCESS) {
        RK_LOGE("ai set alc right voulme fail, reason = %x", result);
        goto __FAILED;
    }

    result = RK_MPI_AI_Enable(aiDevId);
    if (result != 0) {
        RK_LOGE("ai enable fail, reason = %d", result);
        goto __FAILED;
    }

    return RK_SUCCESS;
__FAILED:
    return RK_FAILURE;
}

static RK_S32 test_set_channel_params_ai() {
    AUDIO_DEV aiDevId = 0;
    AI_CHN aiChn = 0;
    RK_S32 result = 0;
    AI_CHN_PARAM_S pstParams;

    //wqy aiDevId = 0, aiChn = 0
    printf("test_set_channel_params_ai, aiChn = %d, aiDevId = %d\n", aiChn, aiDevId);
    memset(&pstParams, 0, sizeof(AI_CHN_PARAM_S));
    pstParams.s32UsrFrmDepth = 4;
    result = RK_MPI_AI_SetChnParam(aiDevId, aiChn, &pstParams);
    if (result != RK_SUCCESS) {
        RK_LOGE("ai set channel params, aiChn = %d", aiChn);
        return RK_FAILURE;
    }

    return RK_SUCCESS;
}

FILE *gFp = NULL;
int g_wakeup_status = 0;
int g_record_status = 0;
typedef void (*pduiPlusLiteSspeCallback)(int);
extern void registerDuiPlusLiteSspeCallback(pduiPlusLiteSspeCallback callback);
int g_wakeup_time = 0;

void duiPlusWakeUpStatusCallback(int status) {
    printf("mpi_audio, duiPlusWakeUpStatusCallback, status = %d\n", status);
    g_wakeup_status = status;

    g_wakeup_time = time(NULL);
    gFp = fopen("/tmp/cap_out.pcm", "w+");
}
void* getDataThread(void * ptr) {
    AUDIO_FRAME_S getFrame;
    RK_S32 s32MilliSec = -1;
    RK_S32 result = 0;
    int s32DevId = 0;
    int s32ChnIndex = 0;

    int current_time = time(NULL);
    int dute_time = 0;

    //hide the ai record file, use the fwrite, own write the audio
    //char record_file_dir[64] = "/tmp";
    //char record_file_name[64] = "cap_out.pcm";
    //printf("getDataThread, record_file_dir=%s...\n", record_file_dir);
    // AUDIO_SAVE_FILE_INFO_S save;
    // save.bCfg = RK_TRUE;
    // save.u32FileSize = 1024;
    // snprintf(save.aFilePath, sizeof(save.aFilePath), "%s", record_file_dir);
    // snprintf(save.aFileName, sizeof(save.aFileName), "%s", record_file_name);
    // RK_MPI_AI_SaveFile(s32DevId, s32ChnIndex, &save);

    while(1) {
        result = RK_MPI_AI_GetFrame(s32DevId, s32ChnIndex, &getFrame, RK_NULL, s32MilliSec);
        if (result == 0) {
            void* data = RK_MPI_MB_Handle2VirAddr(getFrame.pMbBlk);
            RK_LOGV("data = %p, len = %d", data, getFrame.u32Len);
            printf("wqy-->data = %p, len = %d\n", data, getFrame.u32Len);
            if (getFrame.u32Len <= 0) {
                RK_LOGD("get ai frame end");
                break;
            }

            if (g_wakeup_status == 0) {
                //printf("wqy feed the duiplus sspe\n");
                duiplusFeedBuff(data, getFrame.u32Len);
            } else {
                fwrite(data, getFrame.u32Len , 1, gFp);
                printf("write cap_out.pcm...\n");
                current_time = time(NULL);
                dute_time = current_time - g_wakeup_time;
                if (dute_time > 2) {
                    g_wakeup_status = 0;
                    printf("record time is ok, break\n");
                    fclose(gFp);
                    break;
                }
            }
            

            RK_MPI_AI_ReleaseFrame(s32DevId, s32ChnIndex, &getFrame, RK_NULL);
        }

        //printf("RK_MPI_AI_GetFrame next\n");
    }

    pthread_exit(NULL);
    return RK_NULL;
}

RK_S32 test_deinit_mpi_ai() {
    RK_S32 result;
    int s32DevId = 0;
    int s32ChnIndex = 0;

    result = RK_MPI_AMIX_SetControl(s32DevId, "I2STDM Digital Loopback Mode", (char *)"Disabled");
    if (result != RK_SUCCESS) {
        RK_LOGE("ai set I2STDM Digital Loopback Mode fail, reason = %x", result);
        return RK_FAILURE;
    }

    RK_MPI_AI_DisableReSmp(s32DevId, s32ChnIndex);
    
    result = RK_MPI_AI_DisableChn(s32DevId, s32ChnIndex);
    if (result != 0) {
        RK_LOGE("ai disable channel fail, reason = %d", result);
        return RK_FAILURE;
    }

    result =  RK_MPI_AI_Disable(s32DevId);
    if (result != 0) {
        RK_LOGE("ai disable fail, reason = %d", result);
        return RK_FAILURE;
    }

    return RK_SUCCESS;
}

#define POPEN_SIZE 1024
int pcm2wav_cmd() {
    FILE *fp;
    char output[POPEN_SIZE];
    printf("pcm2wav_cmd begin...\n");

    fp = popen("/data/pcm2wav -s /tmp/cap_out.pcm -d /tmp/cap_out.wav", "r");
    if (fp == NULL) {
        fprintf(stderr, "pcm2wav_cmd popen failed.\n");
        return -1;
    }

    while (fgets(output, POPEN_SIZE, fp) != NULL) {
        printf("%s", output);
    }

    printf("pcm2wav_cmd end...\n");
    pclose(fp);
    return 0;
}

void duiplus_wakup_init() {
    printf("duiplus_wakup_init...\n");
    duiplus_init();

    registerDuiPlusLiteSspeCallback(duiPlusWakeUpStatusCallback);
}

int mpi_ai_record() {
    int s32DevId = 0;
    int s32ChnIndex = 0;

    RK_MPI_SYS_Init();

    if (test_open_device_ai() != RK_SUCCESS) {
        printf("test_open_device_ai error\n");
        return -1;
    }

    RK_S32 result = RK_SUCCESS;
    result = test_set_channel_params_ai();
    if (result != RK_SUCCESS) {
        printf("test_set_channel_params_ai, error\n");
        return -1;
    }

    result =  RK_MPI_AI_EnableChn(s32DevId, s32ChnIndex);
    if (result != 0) {
        RK_LOGE("ai enable channel fail, aiChn = %d, reason = %x", s32ChnIndex, result);
        return -1;
    }

    pthread_t tidGet;
    pthread_create(&tidGet, RK_NULL, getDataThread, NULL);

    pthread_join(tidGet, RK_NULL);

    printf("getDataThread end, ready test_deinit_mpi_ai\n");
    // deinit ai
    test_deinit_mpi_ai();

    pcm2wav_cmd();
}